package automaton.efsm;

import java.util.ArrayList;

public class NondefiniteEFSM extends AbstractEFSM {
	public static double MIN_PHEROMONE_VALUE = 0.001;
	public ArrayList<NondefiniteEFSM.Transition>[][] transitions;
	private int numberOfStates;
	private int numberOfExternalInfluences;
	private int initialState;	

	//for each state - symbols that have already been chosen
	public ArrayList<Integer>[] chosenSymbols; 

	public NondefiniteEFSM(int numberOfStates, int numberOfExternalInfluences, ArrayList[][] transitions) {
		this.numberOfStates = numberOfStates;
		this.numberOfExternalInfluences = numberOfExternalInfluences;
		this.transitions = transitions;
		chosenSymbols = new ArrayList[numberOfStates];
		for (int i = 0; i < numberOfStates; i++) {
			chosenSymbols[i] = new ArrayList<Integer>();
		}
	}
		
	@Override
	public int getInitialState() {
		return initialState;
	}

	@Override
	public int getNumberOfStates() {
		return numberOfStates;
	}
 
	public ArrayList<Transition> getTransition(int state, int action) {
		return transitions[state][action];
	}

	@Override
	public void setInitialState(int state) {
		this.initialState = state;
	}
	
	public String toString() {
		String s = "";
		for (int i = 0; i < numberOfStates; i++) {
			for (int j = 0; j < 2; j++) {
				s += "(" + i + ", " + j + ")\n";
				for (int k = 0; k < transitions[i][j].size(); k++) {
					s += "    " + transitions[i][j].get(k) + "\n";
				}			
				s += "\n"; 
			}
			s += "\n";
		}
		return s;
	}

	@Override
	public int getNumberOfExternalInfluences() {
		return numberOfExternalInfluences;
	}
	
	public static class Transition implements AbstractEFSM.Transition, Comparable<NondefiniteEFSM.Transition> {
		private final int startState;
		private final int endState;
		private ArrayList<String> actions;
		private int symbol;	
		private double pheromone;				
		
		public Transition(int startState, int endState, ArrayList<String> actions, int symbol) {
			this.startState = startState;
			this.endState = endState;
			this.actions = (ArrayList<String>) actions.clone();
			this.symbol = symbol;
			pheromone = MIN_PHEROMONE_VALUE;
		}			
		
		public boolean equals(Transition other) {
			boolean first = (this.startState == other.startState &&
					this.endState == other.endState && 
					this.symbol == other.symbol);
			
			if (!first || actions.size() != other.actions.size()) {
				return false;
			}
			
			for (int i = 0; i < actions.size(); i++) {
				if (!actions.get(i).equals(other.actions.get(i))) {
					return false;
				}
			}
			return true;
		}
		
		public int compareTo(NondefiniteEFSM.Transition other) {
			return Double.compare(other.pheromone, this.getPheromone());
		}

		@Override
		public ArrayList<String> getActions() {
			return (ArrayList<String>) actions.clone();
		}
		
		@Override
		public int getStartState() {
			return startState;
		}

		@Override
		public int getEndState() {
			return endState;
		}

		public void setPheromone(double pheromone) {
			this.pheromone = pheromone;
		}

		public double getPheromone() {
			return pheromone;
		}
		
		@Override
		public automaton.AbstractAutomaton.Transition setEndState(int state) {
			return new Transition(startState, state, actions, symbol);
		}	
		
		public String toString() {
			return "(" + endState + ", " + actions + ", " + pheromone + ")";			
		}

		public int getSymbol() {
			return symbol;
		}
		
		public void setSymbol(int symbol) {
			this.symbol = symbol;
		}
		
		public void setActions(ArrayList<String> actions) {
			this.actions = (ArrayList<String>) actions.clone();
		}
	}
}
